unit Interface_MainWnd;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, ToolWin, Menus, ExtCtrls, StdCtrls, Core_Types, Core_FileOperaions, Core_SettingsEngine, ShellAPI;

type
  TWndMain = class(TForm)
    MainMenu: TMainMenu;
    File1: TMenuItem;
    LottBarTop: TToolBar;
    ToolBarBottom: TToolBar;
    LPanel: TPanel;
    RPanel: TPanel;
    Splitter1: TSplitter;
    LList: TListBox;
    RList: TListBox;
    LCapt: TPanel;
    RCapt: TPanel;
    SelectDrives1: TMenuItem;
    SelectRightDrives1: TMenuItem;
    Left1: TMenuItem;
    Right1: TMenuItem;
    LStatusBar: TStatusBar;
    RStatusBar: TStatusBar;
    ToolButton1: TToolButton;
    ToolButton2: TToolButton;
    ToolButton3: TToolButton;
    ToolButton4: TToolButton;
    ToolButton5: TToolButton;
    ToolButton6: TToolButton;
    ToolButton7: TToolButton;
    Commands1: TMenuItem;
    View1: TMenuItem;
    Edit1: TMenuItem;
    Copy1: TMenuItem;
    Movie1: TMenuItem;
    MkDir1: TMenuItem;
    Delete1: TMenuItem;
    TopRefresh: TToolButton;
    LHeader: THeader;
    RHeader: THeader;
    Config1: TMenuItem;
    Plugins1: TMenuItem;
    ShowConsole1: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure RCaptClick(Sender: TObject);
    procedure LCaptClick(Sender: TObject);
    procedure LListClick(Sender: TObject);
    procedure RListClick(Sender: TObject);
    procedure LListDrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    procedure RListEnter(Sender: TObject);
    procedure LListEnter(Sender: TObject);
    procedure LListDblClick(Sender: TObject);
    procedure SelectDrives1Click(Sender: TObject);
    procedure SelectRightDrives1Click(Sender: TObject);
    procedure LListKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure ToolBarBottomResize(Sender: TObject);
    procedure MkDir1Click(Sender: TObject);
    procedure Delete1Click(Sender: TObject);
    procedure TopRefreshClick(Sender: TObject);
    procedure LHeaderSized(Sender: TObject; ASection, AWidth: Integer);
    procedure RHeaderSized(Sender: TObject; ASection, AWidth: Integer);
    procedure Config1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure View1Click(Sender: TObject);
    procedure Copy1Click(Sender: TObject);
    procedure Movie1Click(Sender: TObject);
    procedure ToolButton1Click(Sender: TObject);
    procedure ToolButton3Click(Sender: TObject);
    procedure ToolButton4Click(Sender: TObject);
    procedure ToolButton5Click(Sender: TObject);
    procedure ToolButton6Click(Sender: TObject);
    procedure ToolButton7Click(Sender: TObject);
    procedure ShowConsole1Click(Sender: TObject);
  private

  public
    LeftContext, RightContext : TListContext;

    LFileList, RFileList: TFileArray;
    ActvePanel : (LeftPanel, RightPanel);

    procedure ListPath(Path, Mask : String; List : PFileArray);
    procedure AttachArrayToListBox(ListBox : TListBox; FArray : PFileArray);
    procedure BrowseList(Path, Mask : String; Left : Boolean);
    procedure SetActivePanel(Left : Boolean);
    procedure SortList(PList : PFileArray; SortBy : TSortType);
    function GetActivePath:String;
    procedure PluginMenuItemClick(Sender : TObject);
    procedure UpdatePanels;
    function GetActiveFileList:PFileArray;
    function GetActiveListBox:TListBox;
  end;

function UI_AddMenuItem(cCaption : PChar; ProcID : Integer):Boolean;
function GetActiveList:PFileArray;
procedure UI_ListPath(Path, Mask : PChar; PList: PFileArray);stdcall;
procedure UI_UpdateLists;

var
  WndMain: TWndMain;

implementation

uses Interface_SelectDrive, Interface_DebugConfig, Core_PluginsEngine,
  Interface_Progress, Interface_SelectView, Interface_Console;

{$R *.dfm}

{ TWndMain }

procedure UI_UpdateLists;
begin
  WndMain.UpdatePanels;
end;

procedure UI_ListPath(Path, Mask : PChar; PList: PFileArray);stdcall;
begin
  WndMain.ListPath(Path, Mask, PList);
  WndMain.SortList(PList, byName);
end;

function GetActiveList:PFileArray;
begin
  if WndMain.ActvePanel = LeftPanel then
    Result := @WndMain.LFileList else
      Result := @WndMain.RFileList;
end;

function UI_AddMenuItem(cCaption : PChar; ProcID : Integer):Boolean;
var
  newMenuItem : TMenuItem;
begin
  newMenuItem := TMenuItem.Create(WndMain.Plugins1);
  newMenuItem.Caption := cCaption;
  newMenuItem.Tag := ProcID;
  newMenuItem.OnClick := WndMain.PluginMenuItemClick;

  WndMain.Plugins1.Add(newMenuItem);

  Result := True;
end;


procedure TWndMain.AttachArrayToListBox(ListBox: TListBox;
  FArray: PFileArray);

var
  i:Integer;
begin
  ListBox.Clear;
  for i := 0 to High(FArray^.Files) do
  begin
    ListBox.Items.Add(FArray^.Files[i].Name);
  end;

  ListBox.ItemIndex := 0;
end;

procedure TWndMain.BrowseList(Path, Mask: String; Left: Boolean);
var
  List : PFileArray;
  I : Integer;
  Lbx : TListBox;
  Dirs : Array of String;
  Sel : String;
begin
  Sel := '';
  if Copy(Path, Length(Path)-2, 2) = '..' then
  begin
    while Pos('\', Path) <> 0 do
    begin
      SetLength(Dirs, Length(Dirs)+1);
      Dirs[High(Dirs)] := Copy(Path, 1, Pos('\', Path)-1);
      Delete(Path, 1, Pos('\', Path));
    end;

    Path := '';
    for I := 0 to High(Dirs)-2 do
    begin
      Path := Path + Dirs[I] + '\';
    end;

    Sel := Dirs[High(dirs)-1];
  end;

  if Left then
  begin
    List := @LFileList;
    LCapt.Caption := Path;
  end else
  begin
    RCapt.Caption := Path;
    List := @RFileList;
  end;
      
  ListPath(Path, Mask, List);

  SortList(List, byName);

  if Left then
  begin
    AttachArrayToListBox(LList, List);
    Lbx := LList;
  end else
  begin
    AttachArrayToListBox(RList, List);
    Lbx := RList;
  end;

  if Sel <> '' then
  begin
    for I := 0 to High(List^.Files) do
    begin
      if List^.Files[I].Name = Sel then
      begin
        Lbx.ItemIndex := I;
        Break;
      end;
    end;
  end;
end;

procedure TWndMain.ListPath(Path, Mask : String; List : PFileArray);
var
  sr : TSearchRec;
begin
  SetLength(List^.Files, 0);
  if FindFirst(Path + Mask, faAnyFile or faDirectory, sr) = 0 then
  begin
    repeat
      if sr.Name <> '.' then
      begin
        SetLength(List^.Files, Length(List^.Files)+1);
        List^.Files[High(List^.Files)].Name := sr.Name;
        List^.Files[High(List^.Files)].Ext := LowerCase( ExtractFileExt(sr.Name) );
        Delete(List^.Files[High(List^.Files)].Ext, 1, 1);
        List^.Files[High(List^.Files)].Dir := (sr.Attr and faDirectory) <> 0;
        List^.Files[High(List^.Files)].Size := sr.Size;
      end;
    until
      FindNext(sr) <> 0;
  end;

  List^.Path := Path;
  List^.Mask := Mask;
end;

procedure TWndMain.FormCreate(Sender: TObject);
begin
  SetLength(RFileList.Files, 0);
  SetLength(LFileList.Files, 0);
  BrowseList(Core_Settings_GetStringValue('MainWnd/LeftPanel/Path', PChar(ExtractFilePath(Application.ExeName))), '*.*', True);
  BrowseList(Core_Settings_GetStringValue('MainWnd/RightPanel/Path', PChar(ExtractFilePath(Application.ExeName))), '*.*', False);

  Width := Core_Settings_GetIntegerValue('MainWnd/Width', 640);
  Height := Core_Settings_GetIntegerValue('MainWnd/Height', 480);
  Left := Core_Settings_GetIntegerValue('MainWnd/Left', Screen.Width div 2 - 320);
  Top := Core_Settings_GetIntegerValue('MainWnd/Top', Screen.Height div 2 - 240);

  if Core_Settings_GetBooleanValue('MainWnd/Maximized', False) then
    WindowState := wsMaximized;
end;

procedure TWndMain.FormResize(Sender: TObject);
begin
  LPanel.Width := ClientWidth div 2;
  ToolBarBottomResize(ToolBarBottom);

  LHeader.SectionWidth[0] := LPanel.Width div 2 + LPanel.Width div 4;
  RHeader.SectionWidth[0] := RPanel.Width div 2 + RPanel.Width div 4;
end;

procedure TWndMain.SetActivePanel(Left: Boolean);
begin
  if Left then
  begin
    ActvePanel := LeftPanel;
    LCapt.Color := clActiveCaption;
    RCapt.Color := clInactiveCaption;
    LList.SetFocus;
  end else
  begin
    ActvePanel := RightPanel;
    LCapt.Color := clInactiveCaption;
    RCapt.Color := clActiveCaption;
    RList.SetFocus;
  end;
end;

procedure TWndMain.RCaptClick(Sender: TObject);
begin
  SetActivePanel(False);
end;

procedure TWndMain.LCaptClick(Sender: TObject);
begin
  SetActivePanel(True);
end;

procedure TWndMain.LListClick(Sender: TObject);
begin
  SetActivePanel(True);
end;

procedure TWndMain.RListClick(Sender: TObject);
begin
  SetActivePanel(False);
end;

procedure TWndMain.SortList(PList: PFileArray; SortBy: TSortType);
  function CmpStrings(str1,str2:string):Boolean;
  begin
    {TODO: Normnal compire!}
    Result := str1[1] > str2[1];
  end;
var
  i,j:Integer;
  tmp : TFile;
begin
  for i := 0 to High(Plist^.Files)-1 do
  begin
    for j := i to High(Plist^.Files) do
    begin
      case SortBy of
        byName:if CmpStrings(PList^.Files[i].Name, PList^.Files[j].Name) then
        begin
          tmp := PList^.Files[i];
          PList^.Files[i] := PList^.Files[j];
          PList^.Files[j] := tmp;
        end;
        bySize:;
        byType:;
        byDate:;
      end;
    end;
  end;

  for i := 0 to High(Plist^.Files)-1 do
  begin
    for j := i to High(Plist^.Files) do
    begin
      if PList^.Files[j].Dir and not PList^.Files[i].Dir then
      begin
        tmp := PList^.Files[i];
        PList^.Files[i] := PList^.Files[j];
        PList^.Files[j] := tmp;
      end;
    end;
  end;
end;

procedure TWndMain.LListDrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  PList : PFileArray;
  Head  : THeader;
begin

  if (Control as TListBox).Name = 'LList' then
  begin
    PList := @LFileList;
    Head := LHeader;
  end else
  begin
    PList := @RFileList;
    Head := RHeader;
  end;

  with (Control as TListBox).Canvas do
  begin
    FillRect(Rect);

    if PList^.Files[Index].Selected then
    begin
      Font.Color := clRed;
    end else
    begin
      Font.Color := clWindowText;
    end;

    if PList^.Files[Index].Dir then
    begin
      Font.Style := Font.Style + [fsBold];
      TextOut(Rect.Left, Rect.Top, '[' + PList^.Files[Index].Name + ']');
    end else
    begin
      Font.Style := Font.Style - [fsBold];
      TextOut(Rect.Left, Rect.Top, PList^.Files[Index].Name);
    end;

    TextOut(Rect.Left + Head.SectionWidth[0], Rect.Top, BytesToSize(PList^.Files[Index].Size));

    if PList^.Files[Index].Time <> 0 then
      TextOut(Rect.Left + Head.SectionWidth[0] + Head.SectionWidth[2], Rect.Top, TimeToStr(FileDateToDateTime(PList^.Files[Index].Time)));
  end;
end;

procedure TWndMain.RListEnter(Sender: TObject);
begin
  SetActivePanel(False);
end;

procedure TWndMain.LListEnter(Sender: TObject);
begin
  SetActivePanel(True);
end;

procedure TWndMain.LListDblClick(Sender: TObject);
var
  PList : PFileArray;
  Capt : TPanel;
  FileName, FileDir : String;
begin
  if (Sender as TListBox).Name = 'LList' then
  begin
    PList := @LFileList;
    Capt := LCapt;
  end else
  begin
    PList := @RFileList;
    Capt := RCapt;
  end;

  if PList^.Files[(Sender as TListBox).ItemIndex].Dir then
  begin
    if (Sender as TListBox).Name = 'LList' then
      BrowseList(Capt.Caption + PList^.Files[(Sender as TListBox).ItemIndex].Name + '\', '*.*', True) else
        BrowseList(Capt.Caption + PList^.Files[(Sender as TListBox).ItemIndex].Name + '\', '*.*', False);
  end else
  begin
    //ShellExecute(Handle, 'open', PChar(GetActivePath + GetActiveFileList^.Files[(Sender as TListBox).ItemIndex].Name), nil, PChar(GetActiveFileList^.Path), SW_SHOWNORMAL);
    FileName := GetActivePath + GetActiveFileList^.Files[(Sender as TListBox).ItemIndex].Name;
    FileDir  := GetActivePath;

    ShellExecute(Handle, 'open', PChar(FileName), nil, PChar(FileDir), SW_SHOWNORMAL);
  end;
end;

procedure TWndMain.SelectDrives1Click(Sender: TObject);
begin
  WndSelectDisk.LeftPan := true;
  WndSelectDisk.ShowModal;
end;

procedure TWndMain.SelectRightDrives1Click(Sender: TObject);
begin
  WndSelectDisk.LeftPan := false;
  WndSelectDisk.ShowModal;
end;

procedure TWndMain.LListKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = VK_RETURN then
    (Sender as TListBox).OnDblClick(Sender);

  if Key = VK_INSERT then
  begin
    if ActvePanel = LeftPanel then
    begin
      LFileList.Files[(Sender as TListBox).ItemIndex].Selected := not LFileList.Files[(Sender as TListBox).ItemIndex].Selected;
      if (Sender as TListBox).ItemIndex <> (Sender as TListBox).Items.Count then
        (Sender as TListBox).ItemIndex := (Sender as TListBox).ItemIndex + 1;
    end else
    begin
      RFileList.Files[(Sender as TListBox).ItemIndex].Selected := not RFileList.Files[(Sender as TListBox).ItemIndex].Selected;
      if (Sender as TListBox).ItemIndex <> (Sender as TListBox).Items.Count then
        (Sender as TListBox).ItemIndex := (Sender as TListBox).ItemIndex + 1;
    end;
  end;

  if Key = VK_SPACE then
  begin
    Cursor := crHourGlass;
    if ActvePanel = LeftPanel then
    begin
      if LFileList.Files[(Sender as TListBox).ItemIndex].Dir then
        SetDirSize(@LFileList, (Sender as TListBox).ItemIndex);
     end else
     begin
      if RFileList.Files[(Sender as TListBox).ItemIndex].Dir then
        SetDirSize(@RFileList, (Sender as TListBox).ItemIndex);
     end;
     Cursor := crDefault;
  end;

  (Sender as TListBox).Repaint;
end;

procedure TWndMain.ToolBarBottomResize(Sender: TObject);
begin
  ToolBarBottom.ButtonWidth := ToolBarBottom.Width div ToolBarBottom.ButtonCount;
end;

procedure TWndMain.MkDir1Click(Sender: TObject);
begin
  MkDir(GetActivePath + InputBox('MkDir', 'MkDir', ''));
  UpdatePanels;
end;

function TWndMain.GetActivePath: String;
begin
  if ActvePanel = LeftPanel then
    Result := LCapt.Caption else
    Result := RCapt.Caption;
end;

procedure TWndMain.UpdatePanels;
var
  LIndex, RIndex : Integer;
begin

  LIndex := LList.ItemIndex;
  RIndex := RList.ItemIndex;

  BrowseList(LCapt.Caption, '*.*', True);
  BrowseList(RCapt.Caption, '*.*', False);

  if LIndex > LList.Items.Count-1 then
    LList.ItemIndex := LList.Items.Count-1 else
      LList.ItemIndex := LIndex;

  if RIndex > RList.Items.Count-1 then
    RList.ItemIndex := RList.Items.Count-1 else
      RList.ItemIndex := RIndex;
end;

procedure TWndMain.Delete1Click(Sender: TObject);
begin
  WndProgress.lblOperation.Caption := 'Delete';
  WndProgress.Show;
  if ActvePanel = LeftPanel then
    DeleteFiles(@LFileList) else
      DeleteFiles(@RFileList);

  UpdatePanels;
  WndProgress.Close;
end;

procedure TWndMain.TopRefreshClick(Sender: TObject);
begin
  UpdatePanels;
end;

procedure TWndMain.LHeaderSized(Sender: TObject; ASection,
  AWidth: Integer);
begin
  LList.Repaint;
end;

procedure TWndMain.RHeaderSized(Sender: TObject; ASection,
  AWidth: Integer);
begin
  RList.Repaint;
end;

procedure TWndMain.Config1Click(Sender: TObject);
begin
  Debug_Config.Show;
end;

procedure TWndMain.FormClose(Sender: TObject; var Action: TCloseAction);
var
  wLeft,wTop,wWidth,wHeight:Integer;
  Fulls : Boolean;
begin

  wLeft := Left;
  wTop := Top;
  wWidth := Width;
  wHeight := Height;
  Fulls := (WindowState = wsMaximized);

  Core_SaveSetting('MainWnd/Width', Sizeof(Integer), @wWidth);
  Core_SaveSetting('MainWnd/Height', Sizeof(Integer), @wHeight);
  Core_SaveSetting('MainWnd/Left', Sizeof(Integer), @wLeft);
  Core_SaveSetting('MainWnd/Top', Sizeof(Integer), @wTop);
  Core_SaveSetting('MainWnd/Maximized', Sizeof(Boolean), @Fulls);

  Core_SaveSetting('MainWnd/LeftPanel/Path', Length(LFileList.Path)+1, @LFileList.Path[1]);
  Core_SaveSetting('MainWnd/RightPanel/Path', Length(RFileList.Path)+1, @RFileList.Path[1]);
end;


procedure TWndMain.PluginMenuItemClick(Sender: TObject);
begin
  RegistredProcs[(Sender as TMenuItem).Tag];
end;

procedure TWndMain.View1Click(Sender: TObject);
begin
  if (GetActiveFileList^.Files[GetActiveListBox.ItemIndex].Name <> '..') and (GetActiveFileList^.Files[GetActiveListBox.ItemIndex].Dir = False) then
  begin
    WndSelectView.FileName := GetActiveFileList^.Path + GetActiveFileList^.Files[GetActiveListBox.ItemIndex].Name;
    WndSelectView.ShowModal;
  end;
end;

function TWndMain.GetActiveFileList: PFileArray;
begin
  if ActvePanel = LeftPanel then
    Result := @LFileList else
      Result := @RFileList;
end;

function TWndMain.GetActiveListBox: TListBox;
begin
  if ActvePanel = LeftPanel then
    Result := LList else
      Result := RList;
end;

procedure TWndMain.Copy1Click(Sender: TObject);
begin
  if ActvePanel = LeftPanel then
    CopyFiles(@LFileList, @RFileList) else
      CopyFiles(@RFileList, @LFileList);

  UpdatePanels;
end;

procedure TWndMain.Movie1Click(Sender: TObject);
begin
  if ActvePanel = LeftPanel then
    CopyFiles(@LFileList, @RFileList, True) else
      CopyFiles(@RFileList, @LFileList, True);

  UpdatePanels;
end;

procedure TWndMain.ToolButton1Click(Sender: TObject);
begin
  View1Click(Sender);
end;

procedure TWndMain.ToolButton3Click(Sender: TObject);
begin
  Copy1Click(Sender);
end;

procedure TWndMain.ToolButton4Click(Sender: TObject);
begin
  Movie1Click(Sender);
end;

procedure TWndMain.ToolButton5Click(Sender: TObject);
begin
  MkDir1Click(Sender);
end;

procedure TWndMain.ToolButton6Click(Sender: TObject);
begin
  Delete1Click(Sender);
end;

procedure TWndMain.ToolButton7Click(Sender: TObject);
begin
  Close;
end;

procedure TWndMain.ShowConsole1Click(Sender: TObject);
begin
  WndConsole.Show;
end;

end.
